package me.qi.kancha.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import me.qi.kancha.dto.base.BaseDTO;
import me.qi.kancha.dto.core.*;
import me.qi.kancha.mapper.UserMapper;
import me.qi.kancha.service.*;
import me.qi.kancha.service.base.support.PageData;
import me.qi.kancha.support.U;
import me.qi.kancha.vo.user.UserBatchBindVo;
import me.qi.kancha.vo.user.UserDetails;
import me.qi.kancha.vo.user.UserInfo;
import me.qi.kancha.vo.user.UserQueryVo;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户实体模块-service实现
 *
 * @author sun
 * @date 2022-08-21 12:36:21
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, UserDTO>
        implements UserService {

    private final UserMapper userMapper;

    private final EntityRoleService entityRoleService;

    private final RoleService roleService;

    private final EntityAccountService entityAccountService;

    private final RoleRuleService roleRuleService;

    public UserServiceImpl(UserMapper userMapper, EntityRoleService entityRoleService, RoleService roleService, EntityAccountService entityAccountService, RoleRuleService roleRuleService) {
        this.userMapper = userMapper;
        this.entityRoleService = entityRoleService;
        this.roleService = roleService;
        this.entityAccountService = entityAccountService;
        this.roleRuleService = roleRuleService;
    }

    @Override
    public PageData<UserDTO> listPaging(Object paramObj) {
        UserQueryVo param = (UserQueryVo) paramObj;
        LambdaQueryWrapper<UserDTO> wrapper = new LambdaQueryWrapper<>();
        //key
        if (!ObjectUtils.isEmpty(param.getKey())) {
            wrapper.and(queryWrapper -> queryWrapper.eq(UserDTO::getUserid, param.getKey())
                    .or().like(UserDTO::getName, param.getKey())
                    .or().eq(UserDTO::getPosition, param.getKey()));
        }
        //status
        if (!ObjectUtils.isEmpty(param.getStatus())) {
            wrapper.in(UserDTO::getStatus, param.getStatus());
        }
        //disable
        if (!ObjectUtils.isEmpty(param.getEnable())) {
            if (param.getEnable()) {
                wrapper.eq(UserDTO::getEnable, param.getEnable());
            } else {
                wrapper.and(queryWrapper ->
                        queryWrapper.eq(UserDTO::getEnable, param.getEnable())
                                .or().isNull(UserDTO::getEnable));
            }
        }
        //roleCode
        if (!ObjectUtils.isEmpty(param.getRoleCode())) {
            List<EntityRoleDTO> list = entityRoleService.lambdaQuery()
                    .eq(EntityRoleDTO::getRoleCode, param.getRoleCode())
                    .list();
            if (!ObjectUtils.isEmpty(list)) {
                Set<String> ids = list.stream().map(entityRoleDTO -> entityRoleDTO.getEntityId())
                        .collect(Collectors.toSet());
                wrapper.in(BaseDTO::getId, ids);
            }
        }
        // deptName
        if (!ObjectUtils.isEmpty(param.getDeptName())) {
            wrapper.like(UserDTO::getFullDeptName, param.getDeptName());
        }
        Page<UserDTO> page = page(param.pageInstance(), wrapper);
        List<String> ids = page.getRecords().stream().map(user -> user.getId()).collect(Collectors.toList());
        if (!ids.isEmpty()) {
            List<EntityRoleDTO> centerList = entityRoleService.lambdaQuery().in(EntityRoleDTO::getEntityId, ids).list();
            Set<Object> codes = centerList.stream().map(obj -> obj.getRoleCode()).collect(Collectors.toSet());
            if (!codes.isEmpty()) {
                Map roleMap = new HashMap();
                roleService.lambdaQuery().in(RoleDTO::getCode, codes).list().forEach(roleDTO -> {
                    roleMap.put(roleDTO.getCode(), roleDTO);
                });
                Map<String, List> map = new HashMap();
                for (EntityRoleDTO entityRoleDTO : centerList) {
                    List list = map.get(entityRoleDTO.getEntityId()) == null
                            ? new ArrayList<>() : map.get(entityRoleDTO.getEntityId());
                    Object o = roleMap.get(entityRoleDTO.getRoleCode());
                    if (!ObjectUtils.isEmpty(o)) {
                        list.add(o);
                    }
                    map.put(entityRoleDTO.getEntityId(), list);
                }
                List<UserDetails> userDetailsList = new ArrayList<>();
                for (UserDTO dto : page.getRecords()) {
                    UserDetails userDetails = new UserDetails();
                    BeanUtils.copyProperties(dto, userDetails);
                    userDetails.setRoles(map.get(dto.getId()));
                    userDetailsList.add(userDetails);
                }
                return new PageData(page.getTotal(), userDetailsList);
            }
        }
        return new PageData(page);
    }

    @Override
    public boolean bind(UserDTO user, List<String> codes) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("entity_id", user.getId());
        entityRoleService.remove(wrapper);
        if (codes != null && !codes.isEmpty()) {
            List<EntityRoleDTO> list = codes.stream().map(code -> {
                EntityRoleDTO dto = new EntityRoleDTO();
                dto.setEntityName(user.getName());
                dto.setEntityType("用户");
                dto.setEntityId(user.getId());
                dto.setRoleCode(code);
                return dto;
            }).collect(Collectors.toList());
            if (!list.isEmpty()) {
                return entityRoleService.saveBatch(list);
            }
        }
        return true;
    }

    @Override
    public boolean batchBind(UserBatchBindVo param) {
        for (String id : param.getIds()) {
            for (String code : param.getCodes()) {
                EntityRoleDTO dto = new EntityRoleDTO();
                dto.setEntityType("用户");
                dto.setEntityId(id);
                dto.setRoleCode(code);
                UpdateWrapper wrapper = new UpdateWrapper();
                wrapper.eq("entity_id", id);
                wrapper.eq("role_code", code);
                if (!entityRoleService.update(dto, wrapper)) {
                    entityRoleService.save(dto);
                }
            }
        }
        return true;


    }

    /**
     * 根据用户名进行模糊查询用户信息
     *
     * @param name
     * @return
     */
    @Override
    public List<UserInfo> getUserInfosByName(String name) {
        return userMapper.selectList(new LambdaQueryWrapper<UserDTO>()
                .like(UserDTO::getName, name))
                .stream()
                .map(item -> {
                    UserInfo userInfo = new UserInfo();
                    BeanUtils.copyProperties(item, userInfo);
                    return userInfo;
                })
                .collect(Collectors.toList());
    }

    @Override
    public UserDTO detailByAid(String aid) {
        LambdaQueryWrapper<EntityAccountDTO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(EntityAccountDTO::getAccountId, aid);
        EntityAccountDTO entity = entityAccountService.getOne(wrapper);
        if(entity != null) {
            return getById(entity.getEntityId());
        }
        return null;
    }

    @Override
    public List<String> ruleCodes(String id) {
        List<String> roleCodes = entityRoleService.lambdaQuery()
                .in(EntityRoleDTO::getEntityId, new String[]{id, U.clientEntity()})
                .list().stream()
                .map(entityRoleDTO -> entityRoleDTO.getRoleCode())
                .collect(Collectors.toList());
        List<String> ruleCodes = roleRuleService.lambdaQuery()
                .in(RoleRuleDTO::getRoleCode, roleCodes)
                .list().stream()
                .map(roleRuleDTO -> roleRuleDTO.getRuleCode())
                .collect(Collectors.toList());
        return ruleCodes;
    }
}




